<?php

// +----------------------------------------------------------------------
// | User的event操作
// +----------------------------------------------------------------------
// | Copyright (c) 2015-2024 http://www.yicmf.com, All rights reserved.
// +----------------------------------------------------------------------
// | Author: 微尘 <yicmf@qq.com>
// +----------------------------------------------------------------------

namespace app\event\ucenter;

use app\event\file\QrCode;
use app\event\ucenter\Email as EmailEvent;
use app\event\ucenter\UserExperience as UserExperienceEvent;
use app\event\ucenter\UserPoint as UserPointEvent;
use app\model\app\JdOrder as JdOrderModel;
use app\model\app\PddOrder as PddOrderModel;
use app\model\app\TbkOrder as TbkOrderModel;
use app\model\ucenter\MemberInfo as MemberInfoModel;
use app\model\ucenter\EmailHistory;
use app\model\ucenter\User as UserModel;
use app\event\ucenter\Notice as NoticeEvent;
use app\model\ucenter\UserGrade as UserGradeModel;
use app\model\ucenter\UserOauth as UserOauthModel;
use app\model\ucenter\AuthGroup as AuthGroupModel;
use app\model\ucenter\UserToken as UserTokenModel;
use app\model\ucenter\UserMoneyLog as UserMoneyLogModel;
use app\model\ucenter\Sms as SmsModel;
use app\model\wechat\WechatFans as WechatFansModel;
use think\facade\Db;
use think\Exception;
use think\facade\Config;
use think\facade\Cookie;
use think\facade\Event;
use think\facade\Session;
use app\common\event\Base;
use yicmf\tools\HttpService;

class User extends Base
{
    /**
     * @var UserModel
     */
    protected $user;


    /**
     * 退回押金
     * @param int $user_id 会员ID
     */
    public static function area()
    {
        try {
            $users = UserModel::whereNull('reg_area')->select();


            foreach ($users as $user) {

                $ip = $user['create_ip'] || $user['loginip'] || $user['last_login_ip'];
                if ($ip) {
                    $ip = $user['create_ip'] ? $user['create_ip'] : ($user['loginip'] ?: $user['last_login_ip']);

                    $info = \app\model\ucenter\IpPool::where('ip', $ip)->find();
                    if ($info) {
                        if ($info['region_name']) {
                            $user['reg_area'] = $info['region_name'];
                            $user['reg_city'] = $info['city'];
                            $user->save();
                        }
                    } else {
                        \app\model\ucenter\IpPool::create(['ip' => $ip]);
                    }
                }
            }

        } catch (\Exception $e) {

        }
        return true;
    }

    /**
     * 退回押金
     * @param int $user_id 会员ID
     */
    public static function depositBack($user_id)
    {
        try {
            $userInfo = UserModel::where('id', $user_id)->find();
            if (!$userInfo) {
                throw new Exception('用户不存在');
            }
            //符合退款条件
            if ($userInfo['deposit'] <= 0) {
                throw new Exception('您没有押金可以退款');
            }
            $fee = UserMoneyLogModel::where('user_id', $user_id)
                ->where('createtime', '>', time() - 86400 * 365)->where('type', 11)->sum('money');
            if ($fee < 2980) {
                throw new Exception('直推收益未达到2980');
            }
            Db::startTrans();
            self::money($userInfo['deposit'], $userInfo['id'], '初级合伙人押金退款', 2, $userInfo['id']);
            UserModel::where('id', $user_id)->setDec('deposit', $userInfo['deposit']);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return $e->getMessage();
        }
        return true;
    }

    /**
     */
    public static function f3BuserCheck()
    {
        $ids = UserModel::where('is_b_effective', 0)
            ->whereTime('b_time', '<', time() - 86400 * 180)
            ->distinct(true)
            ->column('bid');
        foreach ($ids as $id) {
            self::_effectiveUser($id);
        }
        return true;
    }

    protected static function _effectiveUser($user_id)
    {
        try {
            Db::startTrans();
            $userInfo = UserModel::where('bid', $user_id)
                ->where('pid', '<>', $user_id)
                ->whereTime('b_time', '<', time() - 86400 * 180)
                ->where('is_b_effective', 0)->select();
            foreach ($userInfo as $index => $item) {
                // 已经加入直属180内展业收益不足 业绩值达到99元或邀请1名有效合伙人
                $money = self::get_effective_money($item['id'], $item['b_time']);
                if ($money >= 99) {
                    $item['is_b_effective'] = 1;
                    $item->save();
                } else {
                    $pUser = UserModel::where('pid', $item['id'])->where('is_effective', 1)
                        ->whereTime('effective_time', '>', $item['b_time'])->find();
                    if ($pUser >= 1) {
                        $item['is_b_effective'] = 1;
                        $item->save();
                    }
                }
                if ($item['is_b_effective'] == 0) {
                    // 查询是否有合格中级
                    $cUser = UserModel::where('pid', $item['pid'])->where('bid', $item['pid'])->where('level', 2)->where('is_effective', 1)->find();
                    if ($cUser) {
                        $item['bid'] = $item['pid'];
                        $item['b_time'] = null;
                        $item->save();
                        $cUser['bid'] = $user_id;
                        $cUser['b_time'] = time_format();
                        $cUser->save();
                    }
                }
            }
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return $e->getMessage();
        }
    }

    /**
     * 用户有效状态
     * @param int $user_id 会员ID
     */
    public static function setEffective($user_id)
    {
        try {
            UserModel::where('id', $user_id)->update(['is_effective' => 1, 'effective_time' => time_format()]);
            if (!empty($user['bid'])) {
//                $bUser = UserModel::where('id', $user_id)->find();
//                if ($bUser && $bUser['is_effective'] == 0) {
//                    $bUser['is_effective'] = 1;
//                    $bUser->save();
//                }
                self::levelUp($user['bid']);
            }
        } catch (\Exception $e) {
            $error = $e->getMessage();
        }
        return true;
    }

    /**
     * 用户升级判断
     * @param int $user_id 会员ID
     */
    public static function levelUp($user_id)
    {
        try {
            $bUser = UserModel::where('id', $user_id)->find();
            if ($bUser) {
                // 免费升级
                if ($bUser['level'] == 1) {
                    // F1升级F2
                    $effective_user = UserModel::where('is_effective', 1)
                        ->where('pid', $bUser['id'])
//                        ->where('createtime', '>', time() - 86400 * 365)
                        ->whereTime('effective_time', '>', '- ' . (86400 * 365) . ' day')
                        ->count();
                    if ($effective_user >= 6) {
                        // 升级中级
                        if ($bUser['is_effective'] != 1) {
                            $bUser['is_effective'] = 1;
                            $bUser['effective_time'] = time_format();
                        }
                        $bUser['level'] = 2;
                        $bUser->save();
//                        UserModel::where('id', $user_id)->update(['level' => 2]);
                        if ($bUser['pid']) {
                            $bbUser = UserModel::where('id', $bUser['pid'])->find();
                            if ($bbUser && $bbUser['level'] == 2) {
                                //符合升级老板角色，直邀数量达标
                                self::_levelToF3($bbUser['id']);
                            }
                        }
                        //检查上级是否符合升级老板角色
                    }
                } elseif ($bUser['level'] == 2) {
                    // F2升级F3
                    self::_levelToF3($bUser['id']);
                }

            }
        } catch (\Exception $e) {
            $error = $e->getMessage();
        }
        return true;
    }

    /***
     * 符合升级老板角色
     */
    protected static function _levelToF3($user_id, $bid)
    {
        $user = UserModel::where('id', $user_id)->find();
        //符合升级老板角色，直邀数量达标
        $has = UserModel::where('level', 'in', '2,3')->where('is_effective', 1)
            ->where('pid', $user_id)->count();
        if ($has > 1) {
            //切换下级归属
//            $leftUserIds = UserModel::where('level', 'in', '2,3')->where('is_effective', 1)
//                ->where('pid', $user_id)
//                ->limit(2)->column('id');

            $toUsers = UserModel::where('level', 'in', '2,3')->where('is_effective', 1)
                ->where('pid', $user_id)
                ->limit(2)->select();
            foreach ($toUsers as $toUser) {
                if ($toUser['level'] == 2) {
                    $toUser['bid'] = $user['bid'];
                    $toUser['b_time'] = date('Y-m-d H:i:s', time());
                    $toUser->save();
                } else {
                    // 当前用户已经晋升，查询他的（）
                    UserModel::where('pid', '<>', $user['id'])
                        ->where('bid', $user['id'])
                        ->where('level', 2)
                        ->update(['bid' => $user['bid'], 'b_time' => date('Y-m-d H:i:s', time())]);
                }
            }
            $user['bid'] = $user['pid'];
            $user['level'] = 3;
            $user->save();
//            UserModel::where('id', 'in', $leftUserIds)->update(['bid' => $user['bid'], 'b_time' => date('Y-m-d H:i:s', time())]);
            // 切换等级
//            UserModel::where('id', $user_id)->update(['level' => 3]);
        }
    }

    /**
     * 展业收益，需要给上级分润
     * @return void
     * @throws Exception
     */

    public static function exhibitionIncome($user, $money, $memo, $type, $from_id, $order_no = '', $capital = 0, $channel = '', $modular_id = null)
    {
        $level = MemberInfoModel::where('type', $user['level'])->where('id', '<', 5)->find();
        if (!$level) {
            throw new Exception('等级异常');
        }

        self::money(round($money * $level['fee'], 2), $user['id'], $memo, $type, $from_id, $order_no, $capital, $channel, $modular_id);

        if ($user['bid']) {
            $bUser = UserModel::where('id', $user['bid'])->find();
            if ($bUser) {
                // 同级奖
                $same = MemberInfo::getSame($user, $bUser);
                if ($same > 0) {
//                    self::money(floor(100 * $money * $same), $user['bid'], $memo.'同级奖', 12, $from_id, $order_no, $capital, $channel,$modular_id);
                    self::money(round($money * $same, 2), $user['bid'], $memo, 12, $user['id'], $order_no, $capital, $channel, $modular_id);
                }
                //级差奖
                $same = MemberInfo::getDifferential($user, $bUser);
                if ($same > 0) {
//                    self::money(floor(100 * $money * $same), $user['bid'], $memo.'级差奖', 13, $from_id, $order_no, $capital, $channel,$modular_id);
                    self::money(round($money * $same, 2), $user['bid'], $memo, 13, $user['id'], $order_no, $capital, $channel, $modular_id);
                }
                //培养
                $same = MemberInfo::getBossToBoss($user, $bUser);
                if ($same > 0) {
//                    self::money(floor(100 * $money * $same), $user['bid'], $memo.'培养奖', 17, $from_id, $order_no, $capital, $channel,$modular_id);
                    self::money(round($money * $same, 2), $user['bid'], $memo, 17, $user['id'], $order_no, $capital, $channel, $modular_id);
                }
                if ($bUser['bid']) {
                    // 间接推荐
                    $bbUser = UserModel::where('id', $bUser['bid'])->find();
                    if ($bbUser) {
                        //间推奖，必须是老板等级
                        $same = MemberInfo::getBossIndirectBoss($user, $bUser, $bbUser);
                        if ($same > 0) {
                            //    self::money(round($money * $same, 2), $bUser['bid'], $memo, 22, $user['id'], $order_no, $capital, $channel, $modular_id);
//                            self::money(floor(100 * $money * $same), $bUser['bid'], $memo.'间推奖', 22, $from_id, $order_no, $capital, $channel,$modular_id);
                        }

                        //直接老板,自己不是，给间接培养
                        $same = MemberInfo::getBossIndirect($user, $bUser, $bbUser);
                        if ($same > 0) {
//                            self::money(floor(100 * $money * $same), $bUser['bid'], $memo.'间接培养奖', 17, $from_id, $order_no, $capital, $channel,$modular_id);
                            self::money(round($money * $same, 2), $bUser['bid'], $memo, 17, $user['id'], $order_no, $capital, $channel, $modular_id);
                        }

                    }

                }
            }
        }

        if ($user['is_new'] == 1 && strtotime($user['create_time']) > strtotime('2024-12-10 14:59:59')) {
            // 新人
            if ($user['pid'] && $user['birthday'] && strtotime($user['birthday']) > strtotime('1969-01-01') && strtotime($user['birthday']) < strtotime('2006-12-12')) {
                $pUser = UserModel::where('id', $user['pid'])->find();
                if ($pUser) {
                    UserModel::where('id', $user['id'])->update(['is_new' => 0]);
                    //拉新奖励
                    self::exhibitionIncome($pUser, 9.8, '拉新奖励', 15, $user['id']);
                }
            }

        }
    }

    /**
     * 免提现收入
     * @return void
     * @throws Exception
     */

    public static function freeIncome($user, $money, $memo, $type, $from_id, $order_no = '', $capital = 0, $channel = '', $modular_id = null)
    {

        $user = UserModel::where('id', $user['id'])->find();
        if ($user) {
            $before = $user->money;
            //$after = $user->money + $money;
            $after = function_exists('bcadd') ? bcadd($user->money, $money, 2) : $user->money + $money;
            if ($after < 0) {
                throw new Exception('余额不足！');
            }
            $user['money'] = $after;
            $user['free_balance'] = $money + $user['free_balance'];
            //更新会员信息
            if (!$user->save()) {
                throw new Exception('会员信息变更失败');
            }
            $log = [
                'user_id' => $user['id'],
                'agent_id' => $user['agent_id'],
                'money' => $money,
                'before' => $before,
                'after' => $after,
                'memo' => $memo,
                'type' => $type,
                'is_work' => 0,
                'from_id' => $from_id,
                'order_id' => $order_no,
                'channel' => $channel,
                'modular_id' => $modular_id,
                'capital' => $capital
            ];
            $log['createtime'] = time();
            $log['create_time'] = time_format();
            $log['update_time'] = time_format();
            //写入日志
            UserMoneyLogModel::create($log);
        }
    }

    /**
     * 返佣取消
     */
    public static function exhibitionIncomeBack($user, $memo, $from_id, $order_no = '', $channel = '', $modular_id = null)
    {
        $logs = UserMoneyLogModel::where('from_id', $from_id)
            ->where('order_id', $order_no)
            ->where('channel', $channel)
            ->where('type', '<>', 99)
            ->where('modular_id', $modular_id)
            ->where('is_eversal', 0)
            ->select();
        foreach ($logs as $index => $log) {
            $log['is_eversal'] = 1;
            $log->save();
            self::money(-$log['money'], $log['user_id'], $memo, 99, $user['id'], $order_no, 0, $channel, $modular_id);
        }
    }

    /**
     * 变更会员余额
     * @param int $money 余额
     * @param int $user_id 会员ID
     * @param string $memo 备注
     * @param $type
     * @param $from_id
     * @param $order_no
     * @param $capital
     * @return void
     * @throws Exception
     */
    public static function money($money, $user_id, $memo, $type, $from_id, $order_no = '', $capital = 0, $channel = '', $modular_id = null)
    {
        if (abs($money) < 0.01) {
            return true;
        }
        $user = UserModel::where('id', $user_id)->lock(true)->find();
        if ($user) {
            $before = $user->money;
            //$after = $user->money + $money;
            $after = function_exists('bcadd') ? bcadd($user->money, $money, 2) : $user->money + $money;
            if ($after < 0) {
                throw new Exception('余额不足！');
            }
            $user['money'] = $after;
            //更新会员信息
            if (!$user->save()) {
                throw new Exception('会员信息变更失败');
            }
            $show_type = UserMoneyLogModel::$show_type;
            if (isset($show_type[$type]) && $show_type[$type] == '展业收益') {
                $is_work = 1;
            } elseif (isset($show_type[$type]) && $show_type[$type] == '邀请奖励') {
                $is_work = 2;
            } elseif (isset($show_type[$type]) && $show_type[$type] == '管理奖励') {
                $is_work = 3;
            } else {
                $is_work = 0;
            }
            $log = [
                'user_id' => $user_id,
                'agent_id' => $user['agent_id'],
                'money' => $money,
                'before' => $before,
                'after' => $after,
                'memo' => $memo,
                'type' => $type,
                'is_work' => $is_work,
                'from_id' => $from_id,
                'order_id' => $order_no,
                'channel' => $channel,
                'modular_id' => $modular_id,
                'capital' => $capital
            ];
//            $log['createtime'] = time();
            $log['create_time'] = time_format();
            $log['update_time'] = time_format();
            if ($type == 39) {
                if ($channel == 'tbk') {
                    // 淘宝客
                    $tbk = TbkOrderModel::where('trade_id', $order_no)->find();
                    if ($tbk) {
                        $log['create_time'] = $tbk['receive_time'];
                    }
                } elseif ($channel == 'pdd') {
                    $pdd = PddOrderModel::where('order_sn', $order_no)->find();
                    if ($pdd) {
                        $log['create_time'] = $pdd['receive_time'];
                    }
                } elseif ($channel == 'jd') {
                    $jd = JdOrderModel::where('order_id', $order_no)->find();
                    if ($jd) {
                        $log['create_time'] = $jd['receive_time'];
                    }
                }
            }
            //写入日志
            UserMoneyLogModel::create($log);
            if ($user['level'] == 1 && $is_work ==1)
            {
                //升级F2
                $money_all = self::get_effective_money($user['id']);
                if ($money_all >= 2980) {
                   // 升级中级
                    UserModel::where('id', $user['id'])->update(['level'=>2]);
                    if ($user['is_effective'] != 1) {
                        self::setEffective($user['id']);
                    }else{
                        self::levelUp($user['id']);
                    }
                }
            }
            //  用户有效状态变更
            if ($user['is_effective'] != 1) {
                $money_all = self::get_effective_money($user['id']);
                if ($money_all >= 99) {
                    self::setEffective($user['id']);
                }
            }
        }


    }

    public static function get_effective_money($user_id, $time = null)
    {
        return UserMoneyLogModel::where('user_id', $user_id)
//            ->where('type', 'in', [11, 19, 12, 13, 90, 50, 37, 38, 39, 51, 50, 52])
            ->where('is_eversal', 0)
            ->where('is_work', 1)
            ->when($time, function ($query) use ($time) {
                return $query->whereTime('create_time', '>=', $time);
            })
            ->where('status', 1)
            ->whereTime('create_time', '>', '2024-07-01 00:00:00')
            ->sum('money');
    }

    /**
     * 变更会员积分
     * @param int $score 积分
     * @param int $user_id 会员ID
     * @param string $memo 备注
     */
    public static function score($score, $user_id, $memo, $type, $from_id, $order_no = '')
    {
        $user = UserModel::where('id', $user_id)->find();
        if ($user && $score != 0) {
            $before = $user->score;
            $after = $user->score + $score;
            $user->save(['score' => $after]);

//            $level = self::nextlevel($user_id);
            //更新会员信息
//            $user->save(['score' => $after, 'level' => $level]);
            //写入日志
            Db::name('user_score_log')->insert(['createtime' => time(), 'user_id' => $user_id, 'score' => $score, 'before' => $before, 'after' => $after, 'memo' => $memo, 'type' => $type, 'from_id' => $from_id, 'order_id' => $order_no]);
        }
    }

    /**
     * 获取访客信息
     * @param array $param
     * @param UserModel $user
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     */
    public function customer($param, $user)
    {
        $customer = UserModel::where('short_code', $param['short_code'])->find();
        if ($customer) {
            $data['code'] = 0;
            $data['data'] = $customer;
        } else {
            $data['code'] = 1;
            $data['message'] = '用户不存在';
        }
        return $data;
    }

    public function view($param, $user)
    {
        $customer = UserModel::where('short_code|id', $param['id'])->find();
        if ($customer) {
            $customer['view'] = $customer['view'] + 1;
            $customer->save();
            $data['data'] = $customer['view'];
            $data['code'] = 0;
        } else {
            $data['code'] = 1;
            $data['message'] = '用户不存在';
        }
        return $data;
    }

    /**
     * 生成二维码
     * @param UserModel $user
     * @param bool $build
     * @return string
     * @author 微尘 <yicmf@qq.com>
     * @datetime: 2020/5/17 21:28
     */
    public static function buildRegisterQrCode($user, $build = false)
    {
        $url = url('ucenter/Foreign/register', ['module' => 'index', 'code' => code_encode($user['id'])], true, true);
        $dir = 'invite' . DIRECTORY_SEPARATOR . time_format($user['create_time'], 'Y/d') . DIRECTORY_SEPARATOR;
        $filename = $user['id'] . '.png';
        if (IS_SAFE_MODE) {
            $file = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'qrcode' . DIRECTORY_SEPARATOR . $dir;
        } else {
            $file = app()->getRootPath() . 'uploads' . DIRECTORY_SEPARATOR . 'qrcode' . DIRECTORY_SEPARATOR . $dir;
        }
        if (!is_file($file . $filename) || $build) {
            QrCode::build($url, $filename, $dir);
        }
        return '/uploads/qrcode/' . $dir . $filename;
    }

    /**
     * 生成二维码
     * @param UserModel $user
     * @param bool $build
     * @return string
     * @author 微尘 <yicmf@qq.com>
     * @datetime: 2020/5/17 21:28
     */
    public static function buildStoreQrCode($user, $build = false)
    {
        $url = url('card/Store/index', ['code' => code_encode($user['id'])], true, true);
        $dir = 'store' . DIRECTORY_SEPARATOR . time_format($user['create_time'], 'Y/d') . DIRECTORY_SEPARATOR;
        $filename = $user['id'] . '.png';
        if ($build) {
            QrCode::build($url, $filename, $dir);
        }
        return '/uploads/qrcode/' . $dir . $filename;
    }

    /**
     * 用户等级变更
     * @param UserModel $user
     * @param string $afresh 重新计算
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function gradeReset($user, $afresh = null)
    {
        try {
            if (!is_null($afresh)) {
                $user['user_grade_id'] = 1;
                $user->save();
            }
            // 注册人数
//				$register_user = UserModel::where('invite_id', $user['id'])->where('status', 1)->count();
//				//成交单数
//				$order_count = $user->orders()->where('status', 5)->where('lock_status', 0)->count();
//				//成交总额
//				$order_amount = $user->orders()->where('status', 5)->where('lock_status', 0)->sum('real_amount');
            // 要求全部满足

            $grade = UserGradeModel::where('status', 1)->where('capping_experience', '>=', $user['capping_experience'])->order('capping_experience ASC')->find();
            if (!$grade) {
                throw new Exception('没有发现新等级');
            }

            // 参与购买人数
            $user['user_grade_id'] = $grade['id'];
            $user->save();
//				$level = UserGradeModel::where('status', 1)
////					->where('order_amount', '<=', $order_amount)
////					->where('order_count', '<=', $order_count)
////					->where('register_user', '<=', $register_user)
////					->where('register_user', '<=', $register_user)
//					->order('order_count DESC')
//					->find();
////				if (!$level) {
////					throw new Exception('没有发现新等级');
////				}
            $data['code'] = 0;
            $data['data'] = $grade;
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * @param array $oauth
     * @param UserModel $user
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/2/27 18:57
     */
    public function bindOauth($oauth, $user)
    {
        try {
            // 1. 确认未绑定其他
            if ($user->oauths()->where('channel', $oauth['channel'])->where('status', 1)->find()) {
                throw new Exception('您已经绑定其他账号');
            }
            // 2. 是否已经绑定其他账户
            if (UserModel::has('oauths', ['open_id' => $oauth['open_id'], 'channel' => $oauth['channel'], 'status' => 1])->find()) {
                throw new Exception('【' . $oauth['nickname'] . '】已经被其他账户绑定');
            }
            // 3. 绑定
            $result = $user->oauths()->save($oauth);
            if (!$result) {
                throw new Exception('绑定数据异常');
            }
            $data['code'] = 0;
            $data['message'] = '绑定成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 忘记密码
     * @param $param
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     */
    public function forget($param)
    {
        try {
            // 验证短信验证码
            $account = NoticeEvent::checkDbCode($param['sms_code'], $param['sms_token']);
            // 设置新密码
            $user = UserModel::where('mobile', $account)->find();
            if (!$user) {
                throw new Exception('当前账号未注册');
            }

            $user['password'] = $param['password'];
            $user['salt'] = '';
            if (!$user->save()) {
                throw new Exception('密码变更失败');
            }
            Action::log('user_forget_password', $user, $param);
            $data['code'] = 0;
            $data['message'] = '密码已经修改，请使用新密码登陆';
            $data['data'] = '密码已经修改，请使用新密码登陆';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 注册用户
     * @param array $param
     * @param string $type
     * @return array
     * @author  : 微尘 <yicmf@qq.com>
     */
    public function register(array $param, string $type = 'web'): array
    {
        try {
            Db::startTrans();
            $user['register_method'] = $type;
            if ('oauth' == $type) {
                $user['nickname'] = $param['nickname'];
                $user['avatar'] = $param['avatar'];
            } elseif ('admin' == $type) {
                // 后台注册
                $user['mobile'] = $param['mobile'];
                $user['store_id'] = $param['store_id'];
                $user['auth_manage_group_id'] = $param['auth_manage_group_id'];
                $user['auth_mobile'] = 1;
                $user['nickname'] = $param['nickname'] ?? ('邮箱用户' . rand(10000, 99999));
                $user['password'] = $param['password'];
            } elseif ('oauthBind' == $type) {
                // 短信验证
                if (!empty($param['invite_code'])) {
                    // 解析邀请人;
                    if (false !== strpos(strtolower($param['invite_code']), 'f')) {
                        $param['invite_code'] = str_replace('f', '', strtolower($param['invite_code']));
                    }
                    $inviteUser = UserModel::where('mobile|shareCode', $param['invite_code'])->find();
                    if ($inviteUser) {
                        if ($inviteUser['is_agency'] == 1) {
                            $user['agent_id'] = $inviteUser['id'];
                        } else {
                            $user['agent_id'] = $inviteUser['agent_id'];
                        }
                        $user['pid'] = $inviteUser['id'];
                        $user['bid'] = $inviteUser['id'];
                    } else {
                        throw new Exception('邀请码无效');
                    }
                } else {
                    $inviteUser = UserModel::where('id', 38)->find();
                    if ($inviteUser) {
                        $user['agent_id'] = $inviteUser['agent_id'];
                        $user['pid'] = $inviteUser['id'];
                        $user['bid'] = $inviteUser['id'];
                    }
                }

                $user['password'] = $param['password'];
                $user['username'] = $param['username'];
                $user['mobile'] = $param['mobile'];
                $user['nickname'] = '手机用户' . substr($user['mobile'], 5, 6);
            } elseif ($type == 'one_mobile') {
                $inviteUser = UserModel::where('id', 38)->find();
                if ($inviteUser) {
                    $user['agent_id'] = $inviteUser['agent_id'];
                    $user['pid'] = $inviteUser['id'];
                    $user['bid'] = $inviteUser['id'];
                }
                $user['mobile'] = $param['mobile'];
                $user['password'] = '123456';
                $user['username'] = $param['mobile'];
                $user['mobile'] = $user['mobile'];
                $user['nickname'] = '手机用户' . substr($user['mobile'], 5, 6);
            } elseif ($type == 'activate') {
                // 邮箱验证
                if (isset($param['activate'])) {
                    $email = EmailHistory::where('token', $param['activate'])->whereTime('create_time', '>', '-1 day')->find();
                    if (!$email) {
                        throw new Exception('激活信息异常');
                    }
                    if ($email['address'] != $param['email']) {
                        throw new Exception('激活链接失效，请重新获取');
                    }
                    $email['status'] = 0;
                    $email->save();
                } else {
                    throw new Exception('激活失败');
                }
                $user['email'] = $email['address'];
                $user['username'] = $user['email'];
                $user['auth_email'] = 1;
                $user['password'] = $param['password'];
                $user['nickname'] = '邮箱用户' . rand(10000, 99999);
                if (!empty($email['email']['invite_code'])) {
                    $param['invite_code'] = $email['email']['invite_code'];
                }
            } else {
                if (!empty($param['invite_code'])) {
                    if (false !== strpos(strtolower($param['invite_code']), 'f')) {
                        $param['invite_code'] = str_replace('f', '', strtolower($param['invite_code']));
                    }
                    // 解析邀请人;
                    $inviteUser = UserModel::where('mobile|shareCode', $param['invite_code'])->find();
                    if ($inviteUser) {
                        if ($inviteUser['is_agency'] == 1) {
                            $user['agent_id'] = $inviteUser['id'];
                        } else {
                            $user['agent_id'] = $inviteUser['agent_id'];
                        }
                        $user['pid'] = $inviteUser['id'];
                        $user['bid'] = $inviteUser['id'];
                    } else {
                        throw new Exception('邀请码无效');
                    }
                } else {
                    $inviteUser = UserModel::where('id', 38)->find();
                    if ($inviteUser) {
                        $user['agent_id'] = $inviteUser['id'];
                        $user['pid'] = $inviteUser['id'];
                        $user['bid'] = $inviteUser['id'];
                    }
                }
                $user['mobile'] = NoticeEvent::checkDbCode($param['sms_code'], $param['sms_token']);
                if ($user['mobile'] != $param['mobile']) {
                    throw new Exception('手机跟发送验证码手机不同');
                }
                if (UserModel::where('mobile', $user['mobile'])->find()) {
                    throw new Exception('当前邮箱已经注册');
                }
                $user['username'] = $user['mobile'];
                $user['nickname'] = $param['nickname'] ?? ('手机用户' . rand(10000, 99999));
                $user['password'] = $param['password'];
            }
            $user['avatar_id'] = Config::get('ucenter.avatar_id');
            $user['gender'] = 0;
            $user['level'] = 1;
            $user['pos_level'] = 0;
            $user['logintime'] = 0;
            $user['shareCode'] = UserModel::where('shareCode', '<', '677777')->max('share_code') + 1;
            $user['share_code'] =  $user['shareCode'];
            $user['create_time'] = time_format();
            // 默认等级
            $user['user_grade_id'] = 1;
            $user = UserModel::create($user);
            if (!$user) {
                throw new Exception($user->getError());
            }
            if ('oauth' == $type) {
                $user->oauths()->save($param);
            }

            $user = $this->_formatInfo($user, 'login', 'register');
//            if (isset($user['invite_id'])) {
//                $invite = UserModel::where('id', $user['invite_id'])->find();
//                // 赠送积分
//                if (Config::get('ucenter.invite_new_user') && $invite) {
//                    // 积分
//                    $log = [];
//                    $log['change_code'] = 'invite_user';
//                    $log['point'] = Config::get('ucenter.invite_new_user');
//                    $log['relation_id'] = $user['id'];
//                    UserPointEvent::change($log, $invite);
//                }
//            }
            if ($user['type'] != 99) {
                // 授权商家权限组
//				$user->roles()->save(100);
                // 发送消息
                $message = [];
                $message['type'] = 'register';
                $message['relation_id'] = $user['id'];
                NoticeEvent::send($message, $user);
                // 生成二维码
//				self::buildRegisterQrCode($user, true);
//				self::buildStoreQrCode($user, true);
//                $this->_gift($user);
            }

            Db::commit();
            $data['code'] = 0;
            $data['message'] = '注册成功';
            $data['data']['tips'] = '注册成功';
            $data['data']['user'] = $user;
        } catch (Exception $e) {
            Db::rollback();
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 开通vip
     * /**
     * @param $user
     * @param $model
     * @param $type
     * @return array
     */
    public function openVip($user, $model, $type = 'point')
    {
        try {
            if (!$user) {
                throw new Exception('会员不存在');
            }
            if (strtotime($user['vip_time']) > strtotime('3 years')) {
                throw new Exception('超过最长续期');
            }
            if ($type == 'point') {
                $vip = VipModel::where('id', $model['relation_id'])->find();
                if (!$vip) {
                    throw new Exception('开通异常');
                }
            }
            Db::startTrans();

            if (strtotime($user['vip_time']) > time()) {
                $user['vip_time'] = time_format(strtotime($user['vip_time']) + $vip['duration'] * 86400);
            } else {
                $user['vip_time'] = time_format(time() + $vip['duration'] * 86400);
            }
            $user['is_vip'] = 1;
            $user->save();

            $log = [];
            $log['vip_id'] = $vip['id'];
            $log['total_amount'] = 0;
            $log['price'] = 0;
            $log['payment_code'] = 'point';
            $log['start_time'] = time_format();
            $log['payment_time'] = time_format();
            $log['end_time'] = $user['vip_time'];
            $log['vip_id'] = $vip['id'];
            $user->vips()->save($log);

            Db::commit();
            $data['code'] = 0;
            $data['message'] = '注册成功';
            $data['data'] = $user;
        } catch (Exception $e) {
            Db::rollback();
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 开通vip
     * /**
     * @param $user
     * @param $param
     * @return array
     */
    public function bindInviteCode($param, $user)
    {
        try {
            if (!$user) {
                throw new Exception('会员不存在');
            }

            if ($user['invite_id']) {
                throw new Exception('已经有邀请人');
            }
            $inviteUser = UserModel::where('invite_code', $param['invite_code'])->find();
            if (!$inviteUser) {
                throw new Exception('邀请码不存在');
            }
            if ($inviteUser['id'] == $user['id']) {
                throw new Exception('不能绑定自己为邀请人');
            }
            Db::startTrans();
            $user['invite_id'] = $inviteUser['id'];
            $user->save();
            Db::commit();
            $data['code'] = 0;
            $data['message'] = '绑定成功';
            $data['data'] = $user;
        } catch (Exception $e) {
            Db::rollback();
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 重置密码
     * @param array $param
     * @param string $type
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     */
    public function reset($param)
    {
        try {

            $email = EmailHistory::where('token', $param['activate'])->whereTime('create_time', '>', '-1 day')->find();
            if (!$email) {
                throw new Exception('激活信息异常');
            }
            if ($email['address'] != $param['email']) {
                throw new Exception('激活链接失效，请重新获取');
            }

            $user = UserModel::where('email', $email['address'])->where('status', 1)->where('auth_email', 1)->find();
            if (!$user) {
                throw new Exception('当前用户未注册');
            }
            $email['status'] = 0;
            $email->save();
            if ($param['reset'] == 'login') {
                // 密码强度验证
                $this->_checkNewPassword($param);
                // 登录密码
                $user['password'] = $param['password'];
            } else {
                // 支付密码
                $user['pay_password'] = $param['password'];
            }
            $user->save();
            $data['code'] = 0;
            $data['message'] = '密码重置成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    protected function _checkNewPassword($param)
    {
        try {
            $this->validate($param, 'app\validate\ucenter\User.Changepassword');
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
    /**
     * 注册活动
     * @param $user
     * @throws Exception
     * @author 微尘 <yicmf@qq.com>
     * @datetime: 2020/6/28 21:54
     */
    /**
     * 注册活动
     * @param $user
     * @throws Exception
     * @author 微尘 <yicmf@qq.com>
     */
    protected function _gift($user)
    {
        $point_param = [];
        $point_param['change_code'] = 'gift';
        $point_param['point'] = 10;
        $point_param['relation_id'] = $user['id'];
        $point_param['remark'] = '新客注册赠送10积分';
        $point_param['message'] = '新客注册赠送10积分';
        $admin = UserModel::where('id', Config::get('ucenter.system_notice_from_user_id'))->find();
        UserPointEvent::change($point_param, $user, $admin);
        $param = [];
        $param['change_code'] = 'gift';
        $param['experience'] = 10;
        $param['relation_id'] = $user['id'];
        $param['remark'] = '新客注册赠送验值10';
        $param['message'] = '新客注册赠送经验值10';
        UserExperienceEvent::change($param, $user, $admin);
//			$change = [];
//			$change['change_code'] = 'admin_recharge';
//			$change['amount'] = 1000;
//			$change['remark'] = '演示版赠送1000日元测试体验金';
//			$change['message'] = '演示版赠送1000日元测试体验金';
//			$change['relation_id'] = $user['id'];
//			$admin = UserModel::find(10000);
//			UserBalanceEvent::change($change, $user, $admin);
    }

    /**
     * 管理员修改用户信息
     * @param           $param
     * @param UserModel $admin
     * @return array
     * @author  : 微尘 <yicmf@qq.com>
     */
    public function updateByAdmin($param, $admin)
    {
        try {
            // 验证权限
//				if (!self::isAdministrator($admin)) {
//					throw new Exception('您没有权限');
//				}
            if (empty($param['id'])) {
                // 新增
                $result = $this->register($param, 'admin');
                if (0 != $result['code']) {
                    throw new Exception($result['message']);
                }
                $user = $result['data']['user'];
//					$user['auth_name'] = $param['auth_name'];
//					$user['introduction'] = $param['introduction'];
//					$user['is_vip'] = $param['is_vip'];
//					$user['auth_info'] = $param['auth_info'];
//					$user['qq'] = $param['qq'];
//					$user['wechat'] = $param['wechat'];
//					$user->save();
                $data['message'] = '注册成功';
            } else {
                // 修改
                $user = UserModel::where('id', $param['id'])->where('status', '>', -2)->find();
                if (!$user) {
                    throw new Exception('未发现需要操作用户');
                }

                $user['level'] = $param['level'];
                $user['mobile'] = $param['mobile'];
                $user['nickname'] = $param['nickname'];
                $user['idCardName'] = $param['idCardName'];
                $user['alipay_no'] = $param['alipay_no'];
                if (!empty($param['new_password'])) {
                    $user['password'] = $param['new_password'];
                }

                $user['avatar'] = $param['avatar'];
                $user['sex'] = $param['sex'];
//					$user['auth_name'] = $param['auth_name'];
//					$user['introduction'] = $param['introduction'];
//					$user['is_vip'] = $param['is_vip'];
                $user['wechat'] = $param['wechat'];
                //                $user->categorys = $param['categorys'];
                if (!$user->save()) {
                    throw new Exception('用户信息未更新');
                }
                $data['message'] = '用户信息修改成功';
            }
            $data['data'] = $user;
            $data['code'] = 0;
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 发送激活验证
     * @param UserModel $user
     * @param string $channel
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/2/16 18:06
     */
    public function activate($user, $channel = 'email')
    {
        try {
            if (!$user['email']) {
                throw new Exception('邮箱不存在');
            }
            if (1 == $user['auth_email']) {
                throw new Exception('邮箱已经验证');
            }
            $data = Event::trigger('activate_email', $user, true);
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 更新手机号
     * @param UserModel $user
     * @param           $param
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/2/16 18:07
     */
    public function authMobile($param, $user)
    {
        try {
            // 验证短信
            $mobile = NoticeEvent::checkCode($param['sms_code']);
            // 验证是否已经绑定
            if (UserModel::where('id', '<>', $user['id'])->where('status', 1)->where('mobile', $mobile)->find()) {
                throw new Exception('当前手机号已经被绑定');
            }
            // 更新手机号
            $user['mobile'] = $mobile;
            $user['auth_mobile'] = 1;
            $user->save();
            $data['code'] = 0;
            $data['message'] = '手机号更新成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 验证邮箱
     * @param UserModel $user
     * @param           $param
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/2/16 18:07
     */
    public function authEmail($param, $user)
    {
        try {
            // 验证短信
            $email = NoticeEvent::checkCode($param['email_code']);
            // 验证是否已经绑定
            if (UserModel::where('id', '<>', $user['id'])->where('status', 1)->where('email', $email)->find()) {
                throw new Exception('当前邮箱已经被绑定');
            }
            // 查询是否赠送积分
            if (!$user->points()->where('change_code', 'gift')->where('message', '首次绑定邮箱赠送积分')->find()) {
                $point_param = [];
                $point_param['change_code'] = 'gift';
                $point_param['point'] = Config::get('ucenter.first_bind_mobile_or_email');
                $point_param['relation_id'] = $user['id'];
                $point_param['remark'] = '首次绑定邮箱赠送积分';//
                $point_param['message'] = '首次绑定邮箱赠送积分';
                $admin = UserModel::where('id', Config::get('ucenter.system_notice_from_user_id'))->find();
                UserPointEvent::change($point_param, $user, $admin);
            }
            // 更新邮箱
            $user['email'] = $email;
            $user['auth_email'] = 1;
            $user->save();
            $data['code'] = 0;
            $data['message'] = '邮箱更新成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 更新手机号
     * @param UserModel $user
     * @param           $param
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/2/16 18:07
     */
    public function updateMobile($param, $user)
    {
        try {
            // 验证短信
            $mobile = NoticeEvent::checkCode($param['sms_code']);
            // 更新手机号
            $user['mobile'] = $mobile;
            $user['auth_mobile'] = 1;
            $user->save();
            $data['code'] = 0;
            $data['message'] = '手机号更新成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 获取当前登陆用户，没有登陆返回null.
     * @param string $module 模块
     * @return UserModel|null
     * @author 微尘 <yicmf@qq.com>
     */
    public static function getLogin($module = null)
    {
        if (!Session::has('user_login_' . $module)) {
            return null;
        } else {
            $auth = Session::get('user_login_' . $module);
//				$auth['login_ip'] = request()->ip();
//				$auth['user_agent'] = request()->header('user-agent');
            if ($auth && think_encrypt(json_encode($auth)) == Session::get('user_login_' . $module . '_key')) {

                $re = self::getInfoById($auth['id']);
                if ($re['code'] != 0) {
                    return null;
                } else {
                    $user = $re['data'];
                }
                if ($user && $user['password'] == $auth['password']) {
                    return $user;
                } else {
                    return null;
                }
            } else {
                return null;
            }
        }
    }

    /**
     * 根据角色获取用户
     * @param $role
     * @param int $limit
     * @return UserModel|array|false
     */
    public static function getUsersByRole($role, $limit = 1)
    {
        if (is_numeric($role)) {
            $role = AuthGroupModel::where('id', $role)->find();
        }
        if (!$role) {
            return false;
        }
        if ($limit == 1) {
            return $role->users()->where(env('database.prefix', '') . 'user.status', 1)->find();
        } else {
            return $role->users()->where(env('database.prefix', '') . 'user.status', 1)->limit($limit)->select();
        }
    }

    /**
     * 根据角色判断权限
     * @param UserModel $user
     * @param AuthGroupModel|int $role
     * @return boolean
     */
    public static function isRole($user, $role)
    {
        if (is_numeric($user)) {
            $user = UserModel::where('id', $role)->find();
        }
        if (!$user) {
            return false;
        }
        if (is_numeric($role)) {
            return $user->roles()->where(Config::get('database.prefix') . 'auth_group.id', $role)->find() ? true : false;
        } else {
            return $user->roles()->where(Config::get('database.prefix') . 'auth_group.id', $role['id'])->find() ? true : false;
        }
    }

    /**
     * 检测是否是管理员
     * @param UserModel $user
     * @return bool
     * @author  : 微尘 <yicmf@qq.com>
     */
    public static function isAdministrator($user): bool
    {
        return !is_null($user) && in_array($user['id'], Config::get('ucenter.user_administrator'));
    }

    /**
     * 修改个人资料
     * @param $param
     * @param $user
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function profile($param, $user)
    {
        try {
            // 安全验证
            //数据格式验证
//				$this->validate($param, '\app\validate\ucenter\User.profile');

            $user['nickname'] = $param['nickname'];
            $user['username'] = $param['account'];
            if (!empty($param['avatar_id'])) {
                $user['avatar_id'] = $param['avatar_id'];
            }
            if (!empty($param['birthday'])) {
                $user['birthday'] = $param['birthday'];
            }
            if (!empty($param['qq'])) {
                $user['qq'] = $param['qq'];
            }
            if (!empty($param['wechat'])) {
                $user['wechat'] = $param['wechat'];
            }
//				$user['qq'] = $param['qq'];
//				$user['birthday'] = $param['birthday'];
//				$user['wechat'] = $param['wechat'];
            $user['sex'] = $param['sex'];
            $user['mobile'] = $param['mobile'];
            if (!$user->save()) {
                throw new Exception('信息未更新');
            }
            $data['code'] = 0;
            $data['message'] = '更新成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 修改个人资料
     * @param $param
     * @param $user
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function password_reset($param, $user)
    {
        try {
            // 安全验证
            //数据格式验证
            if (empty($param['email'])) {
                throw new Exception('请填写完整邮箱');
            }
            if ($param['email'] != $user['email']) {
                throw new Exception('请填写正确邮箱');
            }

            // 发送邮件
            $data = EmailEvent::send($param, $user);

//				$data['code'] = 0;
//				$data['message'] = '发送成功，请登录邮箱修改';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 邮箱重置
     * @param $param
     * @param $user
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function email_reset($param, $user)
    {
        try {

            // 安全验证
            if (!self::checkPassword($param['password'], $user)) {
                throw new Exception('密码验证失败');
            }
            //数据格式验证
            if (empty($param['old_email']) || $param['old_email'] != $user['email']) {
                throw new Exception('请填写正确旧邮箱');
            }
            if ($param['email'] == $param['old_email']) {
                throw new Exception('新旧邮箱不可相同');
            }
            if (UserModel::where('email', $param['email'])->where('status', 1)->find()) {
                throw new Exception('当前邮箱已经注册');
            }
            $param['type'] = 'email_reset';
            $param['uid'] = $user['id'];
            // 发送邮件
            $data = EmailEvent::send($param, $user);

            $data['code'] = 0;
            $data['message'] = '发送成功，请登录邮箱修改';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 邮箱确认重置
     * @param $param
     * @param $user
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function email_reset_do($param)
    {
        try {

            $email = EmailHistory::where('token', $param['activate'])->whereTime('create_time', '>', '-1 day')->find();
            if (!$email) {
                throw new Exception('激活信息异常');
            }
            if (empty($email['param']['uid'])) {
                throw new Exception('链接已经失效，请重新获取' . $email['param']['uid']);
            }

            $user = UserModel::where('id', $email['param']['uid'])->find();

            if (!$user) {
                throw new Exception('当前用户未注册');
            }

            // 安全验证
            if (!self::checkPassword($param['password'], $user)) {
                throw new Exception('密码验证失败');
            }

            $user['email'] = $email['address'];
            $user['username'] = $email['address'];
            $user->save();

            $data['code'] = 0;
            $data['message'] = '新邮箱确认成功，请使用新账户登录';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 第三方登录绑定手机号
     * @param $param
     * @return mixed
     * @author  : 微尘 <yicmf@qq.com>
     * @datetime: 2019/3/8 14:05
     */
    public function oauthBind($param)
    {
        try {
            $oauth = UserOauthModel::where('open_id', $param['open_id'])->whereNull('user_id')->find();
            if (!$oauth) {
                throw new Exception('绑定数据异常');
            }

            $param['mobile'] = NoticeEvent::checkDbCode($param['sms_code'], $param['sms_token']);

            $user = UserModel::where('mobile', $param['mobile'])->find();
            if ($user) {
                // 查询是否绑定渠道
                if ($user->oauths()->where('status', 1)->where('channel', $oauth['channel'])->find()) {
                    throw new Exception('当前手机号已经绑定微信，请更换其他手机号');
                }
            } else {
                $param['username'] = $param['mobile'];
                $param['password'] = $param['password'];
                $param['password_confirm'] = $param['password'];
                $param['nickname'] = $oauth['nickname'];
                $param['avatar'] = $oauth['avatar_url'];
                // 注册
                $data = $this->register($param, 'oauthBind');
                if ($data['code'] != 0) {
                    throw new Exception($data['message']);
                } else {
                    $user = $data['data']['user'];
                }
            }
            $oauth['user_id'] = $user['id'];
            $oauth->save();
            $param['id'] = $user['id'];
            $data = $this->login($param, 'api', 'oauth');
            if ($data['code'] !== 0) {
                throw new Exception($data['message']);
            }
            $data['code'] = 0;
            $data['message'] = '绑定成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 验证密码正确性
     * @param string $password 验证的密码
     * @param UserModel|null $user 需要验证的用户，默认登录用户
     * @return bool
     */
    public static function checkPassword($password, $user = null)
    {

        $user_info = UserModel::where('id', $user['id'])->field('salt,password')->find();
        /* 验证用户密码 */
        if (($password && true === password_verify($password, $user_info['password']))
            || ($user_info['salt'] && $user_info['password'] == md5(md5($password) . $user_info['salt']))) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 修改用户密码
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function updatePassword($param, $user): array
    {
        try {
            // 旧密码验证
            if (!self::checkPassword($param['old_password'], $user)) {
                throw new Exception('密码验证失败');
            }
            //数据格式验证
//            $this->validate($param, '\app\validate\ucenter\User.changepassword');

            if ($param['password'] != $param['confirm_password']) {
                throw new Exception('密码不一致');
            }
            // TODO:密码强度验证
            // 安全验证
//				NoticeEvent::checkCode($param['check_code']);
            $user['password'] = $param['password'];
            $user['salt'] = '';
            if (!$user->save()) {
                throw new Exception('密码保存失败');
            }
            $data['code'] = 0;
            $data['data'] = $user;
            $data['message'] = '密码更新成功';
        } catch (\Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 管理员直接修改用户密码
     * @param array $param 验证的密码
     * @param UserModel $admin 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function adminChangePassword($param, $admin): array
    {
        try {
            // 旧密码验证

            //数据格式验证
            $this->validate($param, '\app\validate\ucenter\User.changepassword');

            $user = UserModel::where('id', $param['id'])->find();
            if (!$user) {
                throw new Exception('会员不存在');
            }
            // TODO:密码强度验证
            // 安全验证
//				NoticeEvent::checkCode($param['check_code']);
            $user['password'] = $param['password'];
            if (!$user->save()) {
                throw new Exception('密码保存失败');
            }
            $data['code'] = 0;
            $data['data'] = $user;
            $data['message'] = '密码更新成功';
        } catch (\Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 修改用户支付密码
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function updatePayPassword($param, $user): array
    {
        try {
            // 旧密码验证
            if (!self::checkPassword($param['password'], $user)) {
                throw new Exception('登录密码验证失败');
            }

//            if ($user['pay_password'] && empty($param['old_pay_password'])) {
//                throw new Exception('请填写旧支付密码');
//            }
//            if ($user['pay_password'] && true !== password_verify($param['old_pay_password'], $user['pay_password'])) {
//                throw new Exception('旧支付密码验证失败');
//            }
            //数据格式验证
            if (!$param['pay_password']) {
                throw new Exception('请填写支付密码');
            }
            if ($param['pay_password'] != $param['confirm_pay_password']) {
                throw new Exception('两次密码不同');
            }
            // 安全验证
            $user['pay_password'] = $param['pay_password'];
            if (!$user->save()) {
                throw new Exception('支付密码保存失败');
            }
            $data['code'] = 0;
            $data['data'] = $user;
            $data['message'] = '支付密码更新成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 修改用户密码
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public static function changePwd($param, $user)
    {
        try {

            // TODO:密码强度验证
            // 安全验证
            NoticeEvent::checkCode($param['check_code']);
            $user['password'] = $param['password'];
            if (!$user->save()) {
                throw new Exception('密码保存失败');
            }
            $data['code'] = 0;
            $data['data'] = $user;
            $data['message'] = '密码保存成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 绑定手机号
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function bindWechat($param, $user)
    {
        try {

            // 查询历史绑定
            $oauth = UserOauthModel::where('open_id', $param['open_id'])->where('channel', 'weixin')->find();
            if ($oauth && $oauth['user_id'] != $user['id']) {
                throw new Exception('此微信已经绑定其他账号');
            }
            if (!$oauth) {
                // 新增

                $his = $user->oauths()->where('channel', 'weixin')->find();
                if ($his) {
                    $his->delete();
                }
                $oauth['avatar_url'] = $param['avatar_url'];
                $oauth['nickname'] = $param['nickname'];
                $oauth['open_id'] = $param['open_id'];
                $oauth['sex'] = $param['sex'];
                $oauth['user_id'] = $user['id'];
                $oauth['channel'] = 'weixin';
                $oauth['info'] = $param;

                $oauth = UserOauthModel::create($oauth);
            }
            $data['code'] = 0;
            $data['data'] = $oauth;
            $data['message'] = '手机号更换成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }


    /**
     * 绑定手机号
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function bindMobile($param, $user)
    {
        try {

            $user['mobile'] = NoticeEvent::checkDbCode($param['sms_code'], $param['sms_token']);
            $user['auth_mobile'] = 1;
            if (!$user->save()) {
                throw new Exception('手机号保存失败');
            }
            $data['code'] = 0;
            $data['data'] = $user;
            $data['message'] = '手机号更换成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 绑定手机号
     * @param array $param 验证的密码
     * @param UserModel $user 需要验证的用户
     * @return array
     * @author 微尘 <yicmf@qq.com>
     */
    public function logoff($param, $user)
    {
        try {

            if ($user['realName'] == 1) {
                if ($param['idCard'] != $user['idCard']) {
                    throw new Exception('身份证号码不符');
                }
                if ($param['idCardName'] != $user['idCardName']) {
                    throw new Exception('身份证姓名不符');
                }
            }

            if (self::checkPassword($param['password'], $user) !== true) {
                throw new Exception('密码校验失败');
            }

            $user['status'] = -2;
            if (!$user->save()) {
                throw new Exception('注销失败');
            }
            $data['code'] = 0;
            $data['message'] = '账号已经注销';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 根据token获取用户信息
     * @param $token
     * @return array
     */
    public static function getInfoByToken($token, $module = null)
    {
        try {
            // 暂时不支持单点登录
            $where = UserTokenModel::where('token', $token);
            $user = UserModel::hasWhere('tokens', $where)->find();
            if (!$user) {
                throw new Exception('当前登录信息已经失效，请重新登录', 11001);
            }
            // 更新此数
//				$user->tokens()->where('token', $token)->inc('times')->update();
            $data['code'] = 0;
            $data['data'] = self::_formatInfo($user, $token, $module);
        } catch (Exception $e) {
            $data['code'] = $e->getCode() ?: 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 根据id获取用户信息
     * @param $token
     * @return array
     */
    public static function getInfoById($id, $module = null)
    {
        try {
            $user = UserModel::where('id', $id)->find();
            if (!$user) {
                throw new Exception('用户不存在', 11001);
            }
            $data['code'] = 0;
            $data['data'] = $user;
        } catch (Exception $e) {
            $data['code'] = $e->getCode() ?: 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 根据id获取用户信息
     * @param $token
     * @return array
     */
    public static function loginById($id, $module = null)
    {
        try {
            // 暂时不支持单点登录
            $user = UserModel::where('id', $id)->find();
            if (!$user) {
                throw new Exception('用户不存在', 11001);
            }
            $user['login_count'] = $user['login_count'] + 1;
            $user['last_active_time'] = time_format();
            $user['last_login_time'] = time_format();
            $user['last_login_ip'] = request()->ip();
            $user->save();
            // 更新此数
//				$user->tokens()->where('token', $token)->inc('times')->update();
            $data['code'] = 0;
            $data['data'] = self::_formatInfo($user, null, $module);
        } catch (Exception $e) {
            $data['code'] = $e->getCode() ?: 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 根据id获取用户信息
     * @param $token
     * @return array
     */
    public static function info($user)
    {
        try {
            // 更新此数
//				$user->tokens()->where('token', $token)->inc('times')->update();
            $data['code'] = 0;
            $data['data'] = self::_formatInfo($user, null, $module);
        } catch (Exception $e) {
            $data['code'] = $e->getCode() ?: 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 第三方登录
     * @param array $param 登录信息
     * @return array|mixed
     */
    public function oauthLogin($param): mixed
    {
        try {
            $oauth = UserOauthModel::where('open_id', $param['open_id'])->where('channel', $param['channel'])->where('status', 1)->find();
            if (!$oauth) {
                // 注册
                $oauth = [];
                if ($param['channel'] == 'weixin') {
                    $oauth['avatar_url'] = $param['avatar_url'];
                    $oauth['nickname'] = $param['nickname'];
                    $oauth['open_id'] = $param['open_id'];
                    $oauth['sex'] = $param['sex'];
                    $oauth['channel'] = $param['channel'];
                    $oauth['info'] = $param;


                } elseif ($param['channel'] == 'ios') {
                    $oauth['nickname'] = $param['nickname'];
                    $oauth['open_id'] = $param['open_id'];
                    $oauth['channel'] = $param['channel'];
                    $oauth['info'] = $param;
                }
                if (isset($param['union_id'])) {
                    $oauth['union_id'] = $param['union_id'];
                    // 查询是否关注公众号
                    $fans = WechatFansModel::where('unionid', $oauth['union_id'])->find();
                    if ($fans && $oauth['user_id'])
                    {
                        $oauth['user_id'] = $fans['user_id'];
                    }
                }
                $oauth = UserOauthModel::create($oauth);
            }

            if (isset($oauth) && $oauth['user_id']) {
                $param['id'] = $oauth['user_id'];
                $param['module'] = 'app';
                $data = $this->login($param, 'app', 'oauth');
            } else {
                $data['code'] = 10;
                $data['message'] = '用户未注册，需要绑定';
                $data['data'] = $oauth;
            }
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
        }
        return $data;
    }

    /**
     * 用户登录认证
     * @param array|UserModel $param
     * @param string|null $module
     * @param string $by
     * @return mixed
     * @author 微尘 <yicmf@qq.com>
     */
    public function login($param, string $module = null, string $by = 'password')
    {
        try {
            if (is_null($module) && false === strpos(request()->controller(), 'admin.')) {
                $module = request()->auth_module;;
            } elseif (is_null($module)) {
                $module = 'admin';
            }
            if ($by == 'password' || 'sms_code' == $by) {
                /* 获取用户数据 */

                if ($by == 'password') {
                    if (isset($param['mobile']))
                    {
                        $user = UserModel::where('username', $param['mobile'])->where('status', '>', -2)->find();
                    }else{
                        $user = UserModel::where('username', $param['username'])->where('status', '>', -2)->find();
                    }
                    if (!$user) {
                        Action::log('user_login_error_account', 'user', $param);
                        throw new Exception('当前用户未注册');
                    }
                    if (!self::checkPassword($param['password'], $user)) {
                        // 记录密码异常
                        $this->request->user = $user;
                        Action::log('user_input_password_error', $user, $param);
                        throw new Exception('密码验证错误');
                    }
                    $param['channel'] = '账号密码';
                } else {
                    $mobile = NoticeEvent::checkDbCode($param['sms_code'], $param['sms_token']);
//                    $user = UserModel::where('mobile', $mobile)->where('auth_mobile', 1)->where('status', '>', -2)->find();
                    $user = UserModel::where('mobile', $mobile)->find();
                    if (!$user) {
                        throw new Exception('未查询到用户');
                    }
                    $param['channel'] = '手机短信';
                }
            } elseif ('oauth' == $by) {
                $user = UserModel::where('id', $param['id'])->where('status', '>', -2)->find();
                if (!$user) {
                    throw new Exception('未查询到用户');
                }
            } elseif ('wx' == $by) {
                $oauth = UserOauthModel::where('open_id', $param['openid'])->where('channel', 'weixin')->where('status', 1)->find();
                $token = UserTokenModel::where('token', $param['token'])->whereTime('create_time', '>', '-20 minutes')->find();
                if (!$token) {
                    throw new Exception('未查询到用户');
                }

                $user = UserModel::where('id', $token['user_id'])->where('status', '>', -2)->find();
                if (!$user) {
                    throw new Exception('未查询到用户');
                }
            } elseif ('one_mobile' == $by) {
                $token = HttpService::post('http://v3.uniapp.yunfuye.com/login', json_encode($param));
                $content = $token['content'];
                if (isset($content['code']) && $content['code'] == 0) {
                    $mobile = $content['phoneNumber'];
                } else {
                    throw new Exception($content['error']['message']);
                }
                $user = UserModel::where('mobile', $mobile)->where('status', '>', -2)->find();
                if (!$user) {
                    $reg['mobile'] = $mobile;
                    // 用不存在，自动注册
                    $res = $this->register($reg, 'one_mobile');
                    if ($res['code'] != 0) {
                        throw new Exception($res['message']);
                    }
                    $user = UserModel::where('mobile', $mobile)->where('status', '>', -2)->find();
                    if (!$user) {
                        throw new Exception('注册失败');
                    }
                }
            } else {
                throw new Exception('登录方式不存在');
            }
            $this->_login($user, $param, $module);
            $user = $this->_formatInfo($user, 'login', $module);
            /* 返回用户对象 */
            if (Cookie::has('login_redirect')) {
                $data['url'] = Cookie::get('login_redirect');
                Cookie::delete('login_redirect');
            } else {
                $data['url'] = $this->request->domain() . '/' . $module;
            }

            /* 返回用户对象 */
            $data['code'] = 0;
            $data['data']['user'] = $user;
            $data['message'] = '登录成功';
        } catch (Exception $e) {
            $data['code'] = 1;
            $data['message'] = $e->getMessage();
            $data['line'] = $e->getLine();
            $data['file'] = $e->getFile();
        }
        return $data;
    }

    /**
     * 登录权限以及信息保存
     * @param UserModel $user 要登录的用户
     * @param           $param
     * @param $module
     * @return UserModel
     * @throws Exception
     */
    protected function _login($user, $param, $module)
    {

        // 检查权限
        $this->_checkAccess($user, $param, $module);
        $this->request->user = $user;
        //记录行为
        $param['module'] = $module;
        Action::log('user_login', $user, $param);
        /* 更新登录信息 */
        $user['login_count'] = $user['login_count'] + 1;
        $user['last_active_time'] = time_format();
        $user['last_login_time'] = time_format();
        $user['last_login_ip'] = $this->request->ip();
        $user->save();
        // 保存用户信息
        $auth = [
            'id' => $user['id'],
            'nickname' => $user['nickname'],
            'password' => $user['password'],
            'avatar_url' => $user['avatar_url'],
            'username' => $user['username'],
//				'token' => $user['token']['token'],
            'login_time' => $user['last_login_time'],
            'login_ip' => $user['last_login_ip'],
            'user_agent' => $this->request->header('user-agent'),
        ];
        Session::set('user_login_' . $module, $auth);
        Session::set('user_login_' . $module . '_key', think_encrypt(json_encode($auth)));

        return $user;
    }

    protected function _loginByOauth($param)
    {
        $param['channel'] = '账号密码';
        /* 获取用户数据 */
        $user = UserModel::where('username|mobile|nickname', $param['account'])->where('status', '>', -2)->find();
        if (!$user) {
            throw new Exception('未查询到用户');
        }
        /* 验证用户密码 */
        if (isset($param['type']) && 1 == $param['type']) {
            NoticeEvent::checkCode($param['sms_code']);
        } else {
            if (!self::checkPassword($param['password'], $user)) {
                // 记录密码异常
                Action::log('user_input_password_error', $user, $param);
                throw new Exception('密码验证错误');
            }
        }
        return $user;
    }

    /**
     * 整理用户信息
     * @param UserModel $user
     * @param $token
     * @param $module
     * @return UserModel
     */
    protected static function _formatInfo(UserModel $user, $token = null, $module = null)
    {
        $user = UserModel::where('id', $user['id'])->withoutField('salt,password')->find();
        if ($token == 'login') {
            $token_info = $user->tokens()->save(['platform' => $module]);
        } elseif ($token) {
            $token_info = $user->tokens()->where('token', $token)->find();
            if (!$token_info) {
                throw new Exception('当前token已经失效');
            }
        } else {
            $token_info = $user->tokens()->order('id DESC')->find();
            if (!$token_info) {
                $token_info = $user->tokens()->save(['platform' => $module]);
            }
        }
        $user['b_user'] = UserModel::where('id', $user['bid'])->field('id,nickname,avatar,mobile,level,wechat')->find();
        $user['p_user'] = UserModel::where('id', $user['pid'])->field('id,nickname,avatar,mobile,level,wechat')->find();
        $user['level_info'] = MemberInfoModel::where('type', $user['level'])->find();
//        $user['pos_level'] = UserPosLevelModel::where('user_id', $user['id'])->order('id', 'desc')->find();
        $user['token_info'] = $token_info;
        $user['token'] = $token_info['token'];
        return $user;
    }

    /**
     * 是否显示验证码
     * @param string $channel
     * @return bool
     * @author 微尘 <yicmf@qq.com>
     * @datetime: 2020/7/8 9:36
     */
    public static function showVerify($channel = 'login')
    {
        if ($channel == 'login') {
            // 登录显示
        }
        return false;
    }

    /**
     * 权限检查
     * @param UserModel $user
     * @param array $param
     * @param string $module
     * @throws Exception
     */
    protected function _checkAccess($user, $param, $module)
    {
//			if (1 !== $user['status']) {
//				throw new Exception('用户被禁用！');
//			}
        $allow_ip = Config::get('ucenter.allow_ip');
        if ($allow_ip && !in_array($this->request->ip(), explode('|', $allow_ip))) {
            throw new Exception('当前ip没有开放登录');
        } elseif (in_array($this->request->ip(), explode('|', Config::get('ucenter.deny_ip')))) {
            throw new Exception('当前ip已经禁止登录');
        }
        /*检测是否有当前应用权限*/
        if (!$this->isAdministrator($user)) {
            //                 $group = $user->roles()->where('module','admin')->where('status',1)->find();
            //                 if (! $group) {
            //                     throw new Exception('您没有登陆当前应用权限！');
            //                 }
        }
        // 模块级别权限检测
        $class_name = '\app\\' . $module . '\event\User';
        if (class_exists($class_name) && in_array('moduleAccessCheck', get_class_methods($class_name))) {
            // 权限检测
            $class_name::moduleAccessCheck($user, $param);
        }
    }


    /**
     * 注销登录用户信息
     * @param $module
     * @return bool
     */
    public static function logout($module)
    {

        Session::delete('user_login_' . $module);
        Session::delete('user_login_' . $module . '_key');
        return true;
    }

    /**
     * 用户等级变更
     * @param array $data
     * @return string
     */
    public function userGradeReset($data = [])
    {
        // 获取经验等级
        $users = UserModel::where('status', 1)->select();
        foreach ($users as $index => $user) {
            $this->gradeReset($user, true);
        }
        return 'success';
    }

}
